﻿using System;
using System.Collections.Generic;
using NHibernate;
using NHibernate.Criterion;

namespace Bunian.Data
{
    public class NHibernateDataContext : IDisposable
    {
        private ISession session;

        public NHibernateDataContext()
        {
            session = SessionHelper.GetNewSession();
        }

        #region IDataContext Members

        #region Persistence functions

        public void Add(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException();
            }

            using (ITransaction tx = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
            {
                try
                {
                    session.Save(item);
                    session.Flush();

                    tx.Commit();
                }
                catch
                {
                    tx.Rollback();

                    throw;
                }
            }
        }

        public void Delete(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException();
            }

            using (ITransaction tx = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
            {
                try
                {
                    session.Delete(item);
                    session.Flush();

                    tx.Commit();
                }
                catch
                {
                    tx.Rollback();

                    throw;
                }
            }
        }

        public void Save(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException();
            }

            using (ITransaction tx = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
            {
                try
                {
                    session.Update(item);
                    session.Flush();

                    tx.Commit();
                }
                catch
                {
                    tx.Rollback();

                    throw;
                }
            }
        }

        #endregion

        public IList<T> GetAll<T>() //where T : class, new()
        {
            return GetAll<T>(0, 0);
        }

        public IList<T> GetAll<T>(int pageIndex, int pageSize) //where T : class, new()
        {
            ICriteria criteria = session.CreateCriteria(typeof(T));
            criteria.SetFirstResult(pageIndex * pageSize);
            if (pageSize > 0)
            {
                criteria.SetMaxResults(pageSize);
            }
            return criteria.List<T>();
        }

        public T GetById<T>(object key) where T : class//, new()
        {
            try
            {
                T item = session.Load<T>(key);

                NHibernate.NHibernateUtil.Initialize(item);

                return item;
            }
            catch
            {
                return null;
            }
        }

        public int GetCount<T>()
        {
            ICriteria criteria = session.CreateCriteria(typeof(T));
            criteria.SetProjection(Projections.RowCount());
            return (int)criteria.List()[0];
        }

        public T CustomQuerySingle<T>(string QueryDescription, List<object> Params) where T : class
        {
            try
            {
                IQuery qry = session.CreateQuery(QueryDescription);

                if (null != Params)
                {
                    foreach (var item in Params)
                    {
                        if (item is QueryParameter<string>)
                        {
                            QueryParameter<string> typedItem = (QueryParameter<string>)item;

                            qry.SetString(typedItem.Name, typedItem.Value);
                        }
                        else if (item is QueryParameter<long>)
                        {
                            QueryParameter<long> typedItem = (QueryParameter<long>)item;

                            qry.SetInt64(typedItem.Name, typedItem.Value);
                        }
                        else if (item is QueryParameter<int>)
                        {
                            QueryParameter<int> typedItem = (QueryParameter<int>)item;

                            qry.SetInt32(typedItem.Name, typedItem.Value);
                        }
                    }
                }

                T result = qry.UniqueResult<T>();

                NHibernate.NHibernateUtil.Initialize(result);

                return result;
            }
            catch
            {
                return null;
            }
        }

        public IList<T> CustomQueryList<T>(string QueryDescription, List<object> Params) where T : class
        {
            try
            {
                IQuery qry = session.CreateQuery(QueryDescription);

                if (null != Params)
                {
                    foreach (var item in Params)
                    {
                        if (item is QueryParameter<string>)
                        {
                            QueryParameter<string> typedItem = (QueryParameter<string>)item;

                            qry.SetString(typedItem.Name, typedItem.Value);
                        }
                        else if (item is QueryParameter<long>)
                        {
                            QueryParameter<long> typedItem = (QueryParameter<long>)item;

                            qry.SetInt64(typedItem.Name, typedItem.Value);
                        }
                        else if (item is QueryParameter<int>)
                        {
                            QueryParameter<int> typedItem = (QueryParameter<int>)item;

                            qry.SetInt32(typedItem.Name, typedItem.Value);
                        }
                    }
                }

                IList<T> result = qry.List<T>();

                NHibernate.NHibernateUtil.Initialize(result);

                return result;
            }
            catch
            {
                return null;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            try
            {
                session.Dispose();
            }
            finally
            {
            }
        }

        #endregion
    }
}